home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is part of ixemul.library for the Amiga.
- * Copyright (C) 1991, 1992 Markus M. Wild
- * Changed to avoid buffer overflows by J. Hoehle and
- * restricted output length for: str(n)cat, strlen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <proto/alib.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/tracecntl.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/ioctl_compat.h>
- #include <sys/termios.h>
- #include <exec/types.h>
- #include <libraries/dos.h>
- #include <proto/exec.h>
- #include "ixtrace.h"
-
- #define OUT_WIDTH 80 /* big enough (>30) to hold first information */
-
- static void print_call (FILE *output, struct trace_packet *tp);
-
- int print_all = 0;
- int skip_sigsetmask = 0;
- int skip_calls = 0;
- FILE *output;
- char VERSION[] = "$VER: ixtrace 1.4 (14-Aug-96)";
-
- void
- dummy_handler ()
- {
- }
-
- int
- main (int argc, char *argv[])
- {
- char *logfile = "-";
- struct trace_packet tp;
- struct trace_packet *tpz;
- int *tpz_;
- struct MsgPort *mp;
- int c, in = 0;
-
- memset ((char *) &tp, '\000', sizeof (tp));
- signal (SIGMSG, dummy_handler);
-
- while ((c = getopt (argc, argv, "ailvmzo:c:p:s:n:")) != EOF)
- switch (c)
- {
- case 'a':
- print_all = 1;
- break;
-
- case 'i':
- in = 1;
- break;
-
- case 'l': /* list system calls */
- {
- int i;
-
- for(i=1;i<=MAXCALLS;i=i+2)
- {
- fprintf(stdout,"(%3d) %-25s\t(%3d) %-25s\n",i,call_table[i].name,
- i+1,call_table[i+1].name);
- }
- return 0;
- }
- break;
-
- case 'c': /* system call by name */
- {
- int i;
- int notfound=1; /* Just to make sure that we know if call is found */
- char *callname;
-
- callname=optarg;
-
- for(i=1;i<=MAXCALLS;i++)
- {
- if (!strcmp(callname, call_table[i].name))
- { tp.tp_syscall = i;
- notfound=0;
- break;
- }
- }
- if (notfound)
- {
- fprintf(stderr,"system call [%s] is unknown to ixtrace\n",callname);
- return 1;
- }
- }
- break;
-
- case 'm':
- skip_sigsetmask = 1;
- break;
-
- case 'o':
- logfile = optarg;
- break;
-
- case 'p':
- tp.tp_pid = atoi (optarg);
- break;
-
- case 'n':
- skip_calls = atoi (optarg);
- if (skip_calls < 0)
- {
- fprintf(stderr, "invalid argument for option -n\n");
- exit(1);
- }
- break;
-
- case 's':
- if (!isdigit(optarg[0]))
- {
- fprintf(stderr, "The -s option requires a number\n",MAXCALLS);
- exit(1);
- }
- tp.tp_syscall = atoi (optarg);
- if (tp.tp_syscall > MAXCALLS)
- {
- fprintf(stderr, "System call number is out of range 1-%d\n",MAXCALLS);
- exit(1);
- }
- break;
-
- case 'z': /* you name the calls --in testing-- */
- {
- int i;
- char calls[80]="";
- int notfound=1;
-
- /* Right now this is only the beginning, clear all systems calls.
- In other words, make them all non-interesting. */
- for(i=1;i<=MAXCALLS;i++)
- {
- call_table[i].interesting=0;
- }
- fprintf(stdout,"When done enter \"x\" by itself, followed by a [RETURN]\n");
- do {
- fprintf(stdout,"trace > ");
- gets(calls);
- if (!strcmp("x",calls)) break;
- for(i=1;i<=MAXCALLS;i++)
- {
- if (!strcmp(calls, call_table[i].name))
- { call_table[i].interesting=1;
- notfound=0;
- break;
- }
- }
- if (notfound) fprintf(stderr,"[%s] is unknown to ixtrace, try again\n"
- , calls);
- notfound=1;
- } while(strcmp("x",calls)); /* A lil' over-kill */
-
- }
- break;
- case 'v':
- {
- fprintf(stdout, "%s\n",VERSION+6); /* get rid of the first 7 chars */
- return 0;
- }
- break;
-
- default:
- fprintf (stderr, "%s [-a] [-m] [-l] [-v] [-z] [-c syscall-name] [-n N] [-o logfile] [-p pid] [-s syscall-number]\n", argv[0]);
- fprintf (stderr, " -a trace all calls (else __-calls are skipped)\n");
- fprintf (stderr, " -m skip sigsetmask() calls (they're heavily used inside the library)\n");
- fprintf (stderr, " -i trace entry to functions. Default is exit.\n");
- fprintf (stderr, " -l list system calls (syscall #) [syscall name]\n");
- fprintf (stderr, " -v version\n");
- fprintf (stderr, " -z only trace the syscalls you want to trace\n");
- fprintf (stderr, " -c only trace this syscall (by name)\n");
- fprintf (stderr, " -n skip the first N traces\n");
- fprintf (stderr, " -o log output to logfile (default is stdout)\n");
- fprintf (stderr, " -p only trace process pid (default is to trace all processes)\n");
- fprintf (stderr, " -s only trace this syscall (default is to trace all calls)\n");
-
- return 1;
- }
-
- if (logfile[0] == '-' && !logfile[1])
- output = stdout;
- else
- output = fopen (logfile, "w");
-
- if (!output)
- {
- perror ("fopen");
- return 1;
- }
-
- if ((mp = CreatePort (0, 0)))
- {
- tp.tp_tracer_port = mp;
- if (tracecntl (TRACE_INSTALL_HANDLER, &tp) == 0)
- {
- while (1)
- {
- struct Message *msg;
- long sigs;
-
- sigs = Wait ((1 << mp->mp_SigBit) | SIGBREAKF_CTRL_C);
- while ((msg = GetMsg (mp)))
- {
- if (msg != (struct Message *) &tp)
- {
- fprintf (stderr, "Got alien message! Don't do that ever again ;-)\n");
- }
- else
- {
- if (in)
- tp.tp_action = TRACE_ACTION_JMP;
- if (! tp.tp_is_entry || tp.tp_action == TRACE_ACTION_JMP)
- print_call (output, &tp);
- }
- Signal ((struct Task *) msg->mn_ReplyPort, SIGBREAKF_CTRL_E);
- }
- if (sigs & SIGBREAKF_CTRL_C)
- break;
- }
- tracecntl (TRACE_REMOVE_HANDLER, &tp);
- }
- else
- perror ("tracecntl");
-
- DeletePort (mp);
- }
- else
- perror ("CreatePort");
- }
-
-
- /* should help make things less mystic... */
- #define TP_SCALL(tp) (tp->tp_argv[0])
- /* this is only valid if !tp->tp_is_entry */
- #define TP_RESULT(tp) (tp->tp_argv[1])
- #define TP_ERROR(tp) (* tp->tp_errno)
- /* tp_argv[2] is the return address */
- #define TP_FIRSTARG(tp) (tp->tp_argv[3])
-
- void
- print_call (FILE *output, struct trace_packet *tp)
- {
- char line[OUT_WIDTH+2]; /* for \n\0 */
- char *argfield;
- int space, len;
- struct call *c;
-
- space = sizeof (line) - 1;
- len = sprintf (line, "$%lx: %c", (unsigned long) tp->tp_message.mn_ReplyPort,
- tp->tp_is_entry ? '>' : '<');
- argfield = line + len;
- space -= len;
-
- if (TP_SCALL (tp) > sizeof (call_table) / sizeof (struct call))
- {
- if (tp->tp_is_entry)
- sprintf (argfield, "SYS_%d()\n", TP_SCALL (tp));
- else
- sprintf (argfield, "SYS_%d() = $%lx (%d)\n",
- TP_SCALL (tp), (unsigned long) TP_RESULT (tp), TP_ERROR (tp));
- }
- else
- {
- c = call_table + TP_SCALL (tp);
-
- if ((!print_all && !c->interesting) ||
- (skip_sigsetmask && TP_SCALL (tp) == SYS_sigsetmask))
- return;
-
- /* we can write space-1 real characters in the buffer, \n is not counted */
- c->func (argfield, space-1, c, tp);
- }
-
- if (skip_calls == 0)
- fputs (line, output);
- else
- skip_calls--;
- }
-
- /* the program contained a bug due to the fact that
- * when snprintf or vsnprintf are called with a zero or negative size,
- * they return -1 as an error marker but not any length.
- */
-
- static void
- vp (char *buf, int len, struct call *c, struct trace_packet *tp)
- {
- int nl = snprintf (buf, len+1, "%s", c->name);
-
- len -= nl; if (len <= 0) goto finish;
- buf += nl;
- if (tp->tp_is_entry || !c->rfmt[0])
- vsnprintf (buf, len+1, c->fmt, (_BSD_VA_LIST_) & TP_FIRSTARG (tp));
- else
- {
- nl = vsnprintf (buf, len+1, c->fmt, (_BSD_VA_LIST_) & TP_FIRSTARG (tp));
- len -= nl; if (len <= 0) goto finish;
- buf += nl;
- nl = snprintf (buf, len+1, "=");
- len -= nl; if (len <= 0) goto finish;
- buf += nl;
- nl = vsnprintf (buf, len+1, c->rfmt, (_BSD_VA_LIST_) & TP_RESULT (tp));
- len -= nl; if (len <= 0) goto finish;
- buf += nl;
- nl = snprintf (buf, len+1, " (%d)", TP_ERROR (tp));
- }
-
- finish:
- strcat (buf, "\n");
- }
-
- const char *
- get_fcntl_cmd (int cmd)
- {
- switch (cmd)
- {
- case F_DUPFD:
- return "F_DUPFD";
-
- case F_GETFD:
- return "F_GETFD";
-
- case F_SETFD:
- return "F_SETFD";
-
- case F_GETFL:
- return "F_GETFL";
-
- case F_SETFL:
- return "F_SETFL";
-
- case F_GETOWN:
- return "F_GETOWN";
-
- case F_SETOWN:
- return "F_SETOWN";
-
- #ifdef F_GETLK
- case F_GETLK:
- return "F_GETLK";
- #endif
-
- #ifdef F_SETLK
- case F_SETLK:
- return "F_SETLK";
- #endif
-
- #ifdef F_SETLKW
- case F_SETLKW:
- return "F_SETLKW";
- #endif
-
- default:
- return "F_unknown";
- }
- }
-
- char *
- get_open_mode (int mode)
- {
- static char buf[120];
-
- switch (mode & O_ACCMODE)
- {
- case O_RDONLY:
- strcpy (buf, "O_RDONLY");
- break;
-
- case O_WRONLY:
- strcpy (buf, "O_WRONLY");
- break;
-
- case O_RDWR:
- strcpy (buf, "O_RDWR");
- break;
-
- default:
- strcpy (buf, "O_illegal");
- break;
- }
-
- #define ADD(flag) \
- if (mode & flag) strcat (buf, "|" #flag);
-
- ADD (O_NONBLOCK);
- ADD (O_APPEND);
- ADD (O_SHLOCK);
- ADD (O_EXLOCK);
- ADD (O_ASYNC);
- ADD (O_FSYNC);
- ADD (O_CREAT);
- ADD (O_TRUNC);
- ADD (O_EXCL);
- #undef ADD
-
- return buf;
- }
-
- char *
- get_ioctl_cmd (int cmd)
- {
- static char buf[12];
-
- /* only deal with those commands that are really implemented somehow in
- ixemul.library. The others are dummies anyway, so they don't matter */
-
- switch (cmd)
- {
- case FIONREAD:
- return "FIONREAD";
-
- case FIONBIO:
- return "FIONBIO";
-
- case FIOASYNC:
- /* not yet implemented, but important to know if some program tries
- to use it ! */
- return "FIOASYNC";
-
- case TIOCGETA:
- return "TIOCGETA";
-
- case TIOCSETA:
- return "TIOCSETA";
-
- case TIOCSETAW:
- return "TIOCSETAW";
-
- case TIOCSETAF:
- return "TIOCSETAF";
-
- case TIOCGETP:
- return "TIOCGETP";
-
- case TIOCSETN:
- return "TIOCSETN";
-
- case TIOCSETP:
- return "TIOCSETP";
-
- case TIOCGWINSZ:
- return "TIOCGWINSZ";
-
- case TIOCOUTQ:
- return "TIOCOUTQ";
-
- case TIOCSWINSZ:
- return "TIOCSWINSZ";
-
- default:
- sprintf (buf, "$%lx", (unsigned long) cmd);
- return buf;
- }
- }
-
-
- static void
- vp_fcntl (char *buf, int len, struct call *c, struct trace_packet *tp)
- {
- int *argv = & TP_FIRSTARG (tp);
-
- if (tp->tp_is_entry)
- if (argv[1] == F_GETFL || argv[1] == F_SETFL)
- snprintf (buf, len+1, "fcntl(%d, %s, %s)",
- argv[0], get_fcntl_cmd (argv[1]), get_open_mode (argv[2]));
- else
- snprintf (buf, len+1, "fcntl(%d, %s, %d)",
- argv[0], get_fcntl_cmd (argv[1]), argv[2]);
- else
- if (argv[1] == F_GETFL || argv[1] == F_SETFL)
- snprintf (buf, len+1, "fcntl(%d, %s, %s) = %d (%d)",
- argv[0], get_fcntl_cmd (argv[1]),
- get_open_mode (argv[2]), TP_RESULT (tp), TP_ERROR (tp));
- else
- snprintf (buf, len+1, "fcntl(%d, %s, %d) = %d (%d)",
- argv[0], get_fcntl_cmd (argv[1]), argv[2],
- TP_RESULT (tp), TP_ERROR (tp));
-
- strcat (buf, "\n");
- }
-
-
- static void
- vp_ioctl (char *buf, int len, struct call *c, struct trace_packet *tp)
- {
- int *argv = & TP_FIRSTARG (tp);
-
- if (tp->tp_is_entry)
- snprintf (buf, len+1, "ioctl(%d, %s, $%lx)",
- argv[0], get_ioctl_cmd (argv[1]), argv[2]);
- else
- snprintf (buf, len+1, "ioctl(%d, %s, $%lx) = %d (%d)",
- argv[0], get_ioctl_cmd (argv[1]), argv[2],
- TP_RESULT (tp), TP_ERROR (tp));
-
- strcat (buf, "\n");
- }
-
-
- static void
- vp_open (char *buf, int len, struct call *c, struct trace_packet *tp)
- {
- int *argv = & TP_FIRSTARG (tp);
-
- if (tp->tp_is_entry)
- snprintf (buf, len+1, "open(\"%s\", %s)", argv[0], get_open_mode (argv[1]));
- else
- snprintf (buf, len+1, "open(\"%s\", %s) = %d (%d)", argv[0],
- get_open_mode (argv[1]), TP_RESULT (tp), TP_ERROR (tp));
-
- strcat (buf, "\n");
- }
-
- static void
- vp_pipe (char *buf, int len, struct call *c, struct trace_packet *tp)
- {
- int *argv = & TP_FIRSTARG (tp);
-
- if (tp->tp_is_entry)
- snprintf (buf, len+1, "pipe($%lx)", argv[0]);
- else
- {
- int *pv = (int *) argv[0];
-
- snprintf (buf, len+1, "pipe([%d, %d]) = %d (%d)",
- pv[0], pv[1], TP_RESULT (tp), TP_ERROR (tp));
- }
-
- strcat (buf, "\n");
- }
-